﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chapter13.Code07.CardClient
{
    using Chapter13.Code07.CardLib;

    public class Player
    {
        public string Name { get; private set; }
        public Cards PlayHand { get; private set; }

        private Player()
        {

        }

        public Player(string name)
        {
            Name = name;
            PlayHand = new Cards();
        }

        public bool HasWon()
        {
            Cards tempHand = (Cards)PlayHand.Clone();

            bool fourOfAKind = false;
            bool threeOfAKind = false;
            int fourRank = -1;
            int threeRank = -1;

            int cardsOfRank;
            for (int macthRank = 0; macthRank < 13; macthRank++)
            {
                cardsOfRank = 0;
                foreach (Card c in tempHand)
                {
                    if (c.rank == (Rank)macthRank)
                    {
                        cardsOfRank++;
                    }
                }
                if (cardsOfRank == 4)
                {
                    fourRank = macthRank;
                    fourOfAKind = true;
                    if (cardsOfRank == 3)
                    {
                        return false;
                    }
                    threeRank = macthRank;
                    threeOfAKind = true;
                }
            }

            if (threeOfAKind && fourOfAKind)
            {
                return true;
            }

            if (fourOfAKind || threeOfAKind)
            {
                for (int cardIndex = tempHand.Count - 1; cardIndex >= 0; cardIndex++)
                {
                    if ((tempHand[cardIndex].rank == (Rank)fourRank) || (tempHand[cardIndex].rank == (Rank)threeRank))
                    {
                        tempHand.RemoveAt(cardIndex);
                    }
                }
            }

            bool fourOfASuit = false;
            bool threeOfASuit = false;
            int fourSuit = -1;
            int threeSuit = -1;

            int cardsOfSuit;
            for (int matchSuit = 0; matchSuit < 4; matchSuit++)
            {
                cardsOfSuit = 0;
                foreach (Card c in tempHand)
                {
                    if (c.suit == (Suit)matchSuit)
                    {
                        cardsOfSuit++;
                    }
                }
                if (cardsOfSuit == 7)
                {
                    threeOfASuit = true;
                    threeSuit = matchSuit;
                    fourOfASuit = true;
                    fourSuit = matchSuit;
                }
                if (cardsOfSuit == 4)
                {
                    threeOfASuit = true;
                    threeSuit = matchSuit;
                }
                if (cardsOfSuit == 3)
                {
                    threeOfASuit = true;
                    threeSuit = matchSuit;
                }
            }
            if (!(threeOfASuit || fourOfASuit))
            {
                return false;
            }

            if (tempHand.Count == 7)
            {
                if (!(threeOfASuit && fourOfASuit))
                {
                    return false;
                }

                Cards set1 = new Cards();
                Cards set2 = new Cards();

                if (threeSuit == fourSuit)
                {
                    int maxVal, minVal;
                    GetLimits(tempHand, out maxVal, out minVal);
                    for (int cardIndex = tempHand.Count - 1; cardIndex >= 0; cardIndex--)
                    {
                        if (((int)tempHand[cardIndex].rank < (minVal + 3)) || ((int)tempHand[cardIndex].rank > (maxVal - 3)))
                        {
                            tempHand.RemoveAt(cardIndex);
                        }
                    }
                    if (tempHand.Count != 1)
                    {
                        return false;
                    }
                    if ((tempHand[0].rank == (Rank)(minVal + 3)) || (tempHand[0].rank == (Rank)(maxVal - 3)))
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }

                foreach (Card card in tempHand)
                {
                    if (card.suit == (Suit)threeSuit)
                    {
                        set1.Add(card);
                    }
                    else
                    {
                        set2.Add(card);
                    }
                }

                if (isSequential(set1) && isSequential(set2))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            if (tempHand.Count == 4)
            {
                if (!fourOfASuit)
                {
                    return false;
                }
                if (isSequential(tempHand))
                {
                    return true;
                }
            }

            if (tempHand.Count == 3)
            {
                if (!fourOfASuit)
                {
                    return false;
                }
                if (isSequential(tempHand))
                {
                    return true;
                }
            }

            return false;
        }

        private void GetLimits(Cards cards, out int maxVal, out int minVal)
        {
            maxVal = 0;
            minVal = 14;
            foreach (Card card in cards)
            {
                if ((int)card.rank > maxVal)
                {
                    maxVal = (int)card.rank;
                }
                if ((int)card.rank < minVal)
                {
                    minVal = (int)card.rank;
                }
            }
        }

        private bool isSequential(Cards cards)
        {
            int maxVal, minVal;
            GetLimits(cards, out maxVal, out minVal);
            if ((maxVal - minVal) == (cards.Count - 1))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
